/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.formserver.vmmanager;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.GspAssociationCollection;
import com.inspur.edp.cef.designtime.api.collection.GspFieldCollection;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonModel;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import com.inspur.edp.formserver.viewmodel.collection.VMElementCollection;
import com.inspur.edp.formserver.viewmodel.collection.ViewObjectCollection;
import com.inspur.edp.formserver.viewmodel.json.model.ViewModelDeserializer;
import com.inspur.edp.formserver.viewmodel.json.model.ViewModelSerializer;
import com.inspur.edp.formserver.vmmanager.exception.VmManagerException;
import com.inspur.edp.lcm.metadata.api.IMetadataContent;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.service.RefCommonService;
import com.inspur.edp.lcm.metadata.spi.MetadataTransferSerializer;
import io.iec.edp.caf.commons.exception.ExceptionLevel;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;

public class TransferSerializer implements MetadataTransferSerializer {

  //region getMapper

  private ObjectMapper getMapper() {
    ObjectMapper mapper = new ObjectMapper();
    SimpleModule module = new SimpleModule();
    module.addDeserializer(IGspCommonModel.class, new ViewModelDeserializer());
    module.addSerializer(IGspCommonModel.class, new ViewModelSerializer());
    mapper.registerModule(module);
    return mapper;
  }

  //endregion

  //region 序列化
  public final String serialize(IMetadataContent metadataContent) {
    GspViewModel viewModel = (GspViewModel) ((metadataContent instanceof GspViewModel)
        ? metadataContent : null);
//        dealContent(viewModel);
    String modelJson = null;
    try {
      modelJson = getMapper().writeValueAsString(viewModel);
    } catch (JsonProcessingException e) {
      throw new RuntimeException("ViewModel序列化失败！");
    }
    return modelJson;
  }

  private void dealContent(GspViewModel viewModel) {
    dealObject(viewModel.getMainObject());
  }

  private void dealObject(GspViewObject viewObject) {

    ViewObjectCollection childObjs = viewObject.getContainChildObjects();
    if (childObjs != null && childObjs.size() > 0) {
      childObjs.forEach((childObj) -> {
        dealObject((GspViewObject) childObj);
      });
    }

    VMElementCollection eles = viewObject.getContainElements();
    if (eles != null && eles.size() > 0) {
      eles.forEach((ele) -> {
        dealElement(ele);
      });
    }
  }

  private void dealElement(IGspCommonField element) {
    if (element.getObjectType() != GspElementObjectType.Association) {
      return;
    }

    GspAssociationCollection assos = element.getChildAssociations();
    if (assos != null && assos.size() > 0) {
      assos.forEach((asso) -> {
        dealAssociation(asso);
      });
    }
  }

  private void dealAssociation(GspAssociation association) {

    GspFieldCollection refEles = association.getRefElementCollection();
    if (refEles != null && refEles.size() > 0) {
      refEles.forEach((refEle) -> {
        dealRefElement(association, refEle);
      });
    }
  }

  private void dealRefElement(GspAssociation association, IGspCommonField refElement) {
    if (refElement.getObjectType() != GspElementObjectType.Association) {
      return;
    }
    RefCommonService service = SpringBeanUtils.getBean(RefCommonService.class);
    GspMetadata refMetadata = service.getRefMetadata(association.getRefModelID());
    if (refMetadata == null) {
      throw new VmManagerException("", "",
          "关联be[" + association.getRefModelID() + "] [" + association.getRefModelCode()
              + "]没有获取到。",
          null, ExceptionLevel.Error, false);
    }
    GspBusinessEntity refBe = (GspBusinessEntity) refMetadata.getContent();
    IGspCommonObject refObj = refBe.findObjectById(association.getRefObjectID());
    if (refObj == null) {
      throw new VmManagerException("", "",
          "关联be[" + association.getRefModelCode() + "]中没有获取到节点[" + association.getRefObjectID()
              + "] [" + association.getRefObjectCode() + "]。", null, ExceptionLevel.Error,
          false);
    }

    IGspCommonElement element = refObj.findElement(refElement.getRefElementId());
    if (element == null) {
      throw new VmManagerException("", "",
          "关联be[" + association.getRefModelCode() + "]中没有获取到字段[" + refElement.getRefElementId()
              + "] [" + refElement.getLabelID() + "]。", null, ExceptionLevel.Error, false);
    }

    refElement.getChildAssociations().addAll(element.getChildAssociations().clone());

    dealElement(refElement);
  }
  //endregion


  public final IMetadataContent deserialize(String contentString) {
    try {
      return getMapper().readValue(contentString, GspViewModel.class);
    } catch (JsonProcessingException e) {
      throw new VmManagerException("", "", "vo反序列化失败" + contentString, null, ExceptionLevel.Error,
          false);

    }
  }
}
